package cn.edu.tju.elm.model;

import cn.edu.tju.core.model.BaseEntity;
import cn.edu.tju.core.model.User;
import jakarta.persistence.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 虚拟钱包实体类（充血模型）
 * 包含余额、冻结金额、透支额度等业务数据和业务逻辑
 */
@Entity
@Table(name = "virtual_wallet")
public class VirtualWallet extends BaseEntity {

    /**
     * 可用余额
     */
    @Column(name = "balance", precision = 10, scale = 2, nullable = false)
    private BigDecimal balance = BigDecimal.ZERO;

    /**
     * 冻结金额（如订单待确认的金额）
     */
    @Column(name = "frozen_amount", precision = 10, scale = 2, nullable = false)
    private BigDecimal frozenAmount = BigDecimal.ZERO;

    /**
     * 透支额度（VIP用户专享）
     */
    @Column(name = "overdraft_limit", precision = 10, scale = 2, nullable = false)
    private BigDecimal overdraftLimit = BigDecimal.ZERO;

    /**
     * 已透支金额
     */
    @Column(name = "overdraft_used", precision = 10, scale = 2, nullable = false)
    private BigDecimal overdraftUsed = BigDecimal.ZERO;

    /**
     * 充值奖励累计（用于提现时扣除）
     */
    @Column(name = "bonus_amount", precision = 10, scale = 2, nullable = false)
    private BigDecimal bonusAmount = BigDecimal.ZERO;

    /**
     * 是否为VIP用户
     */
    @Column(name = "is_vip", nullable = false)
    private Boolean isVip = false;

    /**
     * 钱包状态：NORMAL（正常）、FROZEN（冻结）、LOCKED（锁定）
     */
    @Column(name = "status", length = 20, nullable = false)
    private String status = "NORMAL";

    /**
     * 透支开始时间（用于计算利息）
     */
    @Column(name = "overdraft_start_time")
    private LocalDateTime overdraftStartTime;

    /**
     * 日利率（透支利息）
     */
    @Column(name = "interest_rate", precision = 6, scale = 5, nullable = false)
    private BigDecimal interestRate = new BigDecimal("0.0005"); // 默认0.05%日利率

    /**
     * 透支免息天数
     */
    @Column(name = "interest_free_days", nullable = false)
    private Integer interestFreeDays = 30; // 默认30天免息期

    @OneToOne
    @JoinColumn(name = "user_id", nullable = false, unique = true)
    private User user;

    public VirtualWallet() {
    }

    public VirtualWallet(User user) {
        this.user = user;
        this.balance = BigDecimal.ZERO;
        this.frozenAmount = BigDecimal.ZERO;
        this.overdraftLimit = BigDecimal.ZERO;
        this.overdraftUsed = BigDecimal.ZERO;
        this.bonusAmount = BigDecimal.ZERO;
        this.isVip = false;
        this.status = "NORMAL";
    }

    // Getters and Setters
    public BigDecimal getBalance() {
        return balance;
    }

    public void setBalance(BigDecimal balance) {
        this.balance = balance;
    }

    public BigDecimal getFrozenAmount() {
        return frozenAmount;
    }

    public void setFrozenAmount(BigDecimal frozenAmount) {
        this.frozenAmount = frozenAmount;
    }

    public BigDecimal getOverdraftLimit() {
        return overdraftLimit;
    }

    public void setOverdraftLimit(BigDecimal overdraftLimit) {
        this.overdraftLimit = overdraftLimit;
    }

    public BigDecimal getOverdraftUsed() {
        return overdraftUsed;
    }

    public void setOverdraftUsed(BigDecimal overdraftUsed) {
        this.overdraftUsed = overdraftUsed;
    }

    public BigDecimal getBonusAmount() {
        return bonusAmount;
    }

    public void setBonusAmount(BigDecimal bonusAmount) {
        this.bonusAmount = bonusAmount;
    }

    public Boolean getVip() {
        return isVip;
    }

    public void setVip(Boolean vip) {
        isVip = vip;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public LocalDateTime getOverdraftStartTime() {
        return overdraftStartTime;
    }

    public void setOverdraftStartTime(LocalDateTime overdraftStartTime) {
        this.overdraftStartTime = overdraftStartTime;
    }

    public BigDecimal getInterestRate() {
        return interestRate;
    }

    public void setInterestRate(BigDecimal interestRate) {
        this.interestRate = interestRate;
    }

    public Integer getInterestFreeDays() {
        return interestFreeDays;
    }

    public void setInterestFreeDays(Integer interestFreeDays) {
        this.interestFreeDays = interestFreeDays;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    // ==================== 充血模型：业务逻辑方法 ====================

    /**
     * 获取当前可用余额（余额 + 剩余透支额度）
     * @return 可用余额
     */
    public BigDecimal getAvailableBalance() {
        BigDecimal remainingOverdraft = overdraftLimit.subtract(overdraftUsed);
        return balance.add(remainingOverdraft);
    }

    /**
     * 获取实际余额（不包括透支）
     * @return 实际余额
     */
    public BigDecimal getCurrentBalance() {
        return this.balance;
    }

    /**
     * 获取总资产（余额 - 透支已用）
     * @return 总资产
     */
    public BigDecimal getTotalAssets() {
        return balance.subtract(overdraftUsed);
    }

    /**
     * 充值（入账）
     * @param amount 充值金额
     * @param bonus 充值返点金额
     * @throws InvalidAmountException 金额无效异常
     * @throws WalletFrozenException 钱包冻结异常
     */
    public void recharge(BigDecimal amount, BigDecimal bonus) 
            throws InvalidAmountException, WalletFrozenException {
        validateAmount(amount);
        checkWalletStatus();

        this.balance = this.balance.add(amount).add(bonus);
        this.bonusAmount = this.bonusAmount.add(bonus);
    }

    /**
     * 提现（出账）
     * @param amount 提现金额
     * @param fee 手续费
     * @throws InsufficientBalanceException 余额不足异常
     * @throws InvalidAmountException 金额无效异常
     * @throws WalletFrozenException 钱包冻结异常
     */
    public void withdraw(BigDecimal amount, BigDecimal fee) 
            throws InsufficientBalanceException, InvalidAmountException, WalletFrozenException {
        validateAmount(amount);
        checkWalletStatus();

        BigDecimal totalAmount = amount.add(fee);
        
        // 检查余额（提现不能使用透支额度）
        if (this.balance.compareTo(totalAmount) < 0) {
            throw new InsufficientBalanceException("余额不足，当前余额：" + this.balance + "，需要：" + totalAmount);
        }

        // 扣除提现金额和手续费
        this.balance = this.balance.subtract(totalAmount);
        
        // 扣除相应的奖励金额（防止薅羊毛）
        BigDecimal bonusToDeduct = calculateBonusToDeduct(amount);
        this.bonusAmount = this.bonusAmount.subtract(bonusToDeduct);
        if (this.bonusAmount.compareTo(BigDecimal.ZERO) < 0) {
            this.bonusAmount = BigDecimal.ZERO;
        }
    }

    /**
     * 转账支出（支持透支）
     * @param amount 转账金额
     * @throws InsufficientBalanceException 余额不足异常
     * @throws InvalidAmountException 金额无效异常
     * @throws WalletFrozenException 钱包冻结异常
     * @throws OverdraftLimitExceededException 透支超限异常
     */
    public void transfer(BigDecimal amount) 
            throws InsufficientBalanceException, InvalidAmountException, 
                   WalletFrozenException, OverdraftLimitExceededException {
        validateAmount(amount);
        checkWalletStatus();

        // 检查可用余额（包括透支额度）
        if (getAvailableBalance().compareTo(amount) < 0) {
            throw new InsufficientBalanceException(
                "可用余额不足，当前可用：" + getAvailableBalance() + "，需要：" + amount);
        }

        // 先扣除余额
        if (this.balance.compareTo(amount) >= 0) {
            // 余额足够，直接扣除
            this.balance = this.balance.subtract(amount);
        } else {
            // 余额不足，需要使用透支
            BigDecimal overdraftNeeded = amount.subtract(this.balance);
            
            // 检查透支额度
            BigDecimal availableOverdraft = overdraftLimit.subtract(overdraftUsed);
            if (availableOverdraft.compareTo(overdraftNeeded) < 0) {
                throw new OverdraftLimitExceededException(
                    "透支额度不足，可用透支额度：" + availableOverdraft + "，需要：" + overdraftNeeded);
            }

            // 余额清零，增加透支使用金额
            this.balance = BigDecimal.ZERO;
            this.overdraftUsed = this.overdraftUsed.add(overdraftNeeded);
            
            // 记录透支开始时间
            if (this.overdraftStartTime == null) {
                this.overdraftStartTime = LocalDateTime.now();
            }
        }
    }

    /**
     * 收款（入账）
     * @param amount 收款金额
     * @throws InvalidAmountException 金额无效异常
     */
    public void receive(BigDecimal amount) throws InvalidAmountException {
        validateAmount(amount);

        // 如果有透支，优先还款
        if (this.overdraftUsed.compareTo(BigDecimal.ZERO) > 0) {
            if (amount.compareTo(this.overdraftUsed) >= 0) {
                // 金额足够还清透支
                BigDecimal remaining = amount.subtract(this.overdraftUsed);
                this.overdraftUsed = BigDecimal.ZERO;
                this.overdraftStartTime = null;
                this.balance = this.balance.add(remaining);
            } else {
                // 部分还款
                this.overdraftUsed = this.overdraftUsed.subtract(amount);
            }
        } else {
            // 没有透支，直接增加余额
            this.balance = this.balance.add(amount);
        }
    }

    /**
     * 冻结资金
     * @param amount 冻结金额
     * @throws InsufficientBalanceException 余额不足异常
     * @throws InvalidAmountException 金额无效异常
     * @throws WalletFrozenException 钱包冻结异常
     */
    public void freeze(BigDecimal amount)
            throws InsufficientBalanceException, InvalidAmountException, WalletFrozenException, OverdraftLimitExceededException {
        validateAmount(amount);
        checkWalletStatus();

        BigDecimal available = getAvailableBalance();
        if (available.compareTo(amount) < 0) {
            throw new InsufficientBalanceException("可用余额不足，无法冻结");
        }

        if (this.balance.compareTo(amount) >= 0) {
            this.balance = this.balance.subtract(amount);
        } else {
            BigDecimal payByBalance = this.balance;
            this.balance = BigDecimal.ZERO;
            BigDecimal payByOverdraft = amount.subtract(payByBalance);
            BigDecimal availableOverdraft = overdraftLimit.subtract(overdraftUsed);
            if (availableOverdraft.compareTo(payByOverdraft) < 0) {
                throw new OverdraftLimitExceededException("透支额度不足");
            }
            this.overdraftUsed = this.overdraftUsed.add(payByOverdraft);
            if (this.overdraftStartTime == null) {
                this.overdraftStartTime = java.time.LocalDateTime.now();
            }
        }

        this.frozenAmount = this.frozenAmount.add(amount);
    }

    /**
     * 解冻资金
     * @param amount 解冻金额
     * @throws InvalidAmountException 金额无效异常
     */
    public void unfreeze(BigDecimal amount) throws InvalidAmountException {
        validateAmount(amount);

        if (this.frozenAmount.compareTo(amount) < 0) {
            throw new InvalidAmountException("解冻金额超过冻结金额");
        }

        this.frozenAmount = this.frozenAmount.subtract(amount);

        if (this.overdraftUsed.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal repay = amount.min(this.overdraftUsed);
            this.overdraftUsed = this.overdraftUsed.subtract(repay);
            if (this.overdraftUsed.compareTo(BigDecimal.ZERO) == 0) {
                this.overdraftStartTime = null;
            }
            BigDecimal remaining = amount.subtract(repay);
            if (remaining.compareTo(BigDecimal.ZERO) > 0) {
                this.balance = this.balance.add(remaining);
            }
        } else {
            this.balance = this.balance.add(amount);
        }
    }

    /**
     * 扣除冻结资金（如确认收货后扣款）
     * @param amount 扣除金额
     * @throws InvalidAmountException 金额无效异常
     */
    public void deductFrozen(BigDecimal amount) throws InvalidAmountException {
        validateAmount(amount);

        if (this.frozenAmount.compareTo(amount) < 0) {
            throw new InvalidAmountException("扣除金额超过冻结金额");
        }

        this.frozenAmount = this.frozenAmount.subtract(amount);
    }

    /**
     * 还款（偿还透支）
     * @param amount 还款金额
     * @throws InvalidAmountException 金额无效异常
     */
    public void repay(BigDecimal amount) throws InvalidAmountException {
        validateAmount(amount);

        if (this.overdraftUsed.compareTo(BigDecimal.ZERO) == 0) {
            throw new InvalidAmountException("当前无透支，无需还款");
        }

        if (amount.compareTo(this.overdraftUsed) > 0) {
            // 还款金额大于透支金额，多余部分返回余额
            BigDecimal excess = amount.subtract(this.overdraftUsed);
            this.overdraftUsed = BigDecimal.ZERO;
            this.balance = this.balance.add(excess);
            this.overdraftStartTime = null;
        } else {
            // 部分还款
            this.overdraftUsed = this.overdraftUsed.subtract(amount);
            if (this.overdraftUsed.compareTo(BigDecimal.ZERO) == 0) {
                this.overdraftStartTime = null;
            }
        }
    }

    /**
     * 计算透支利息
     * @return 利息金额
     */
    public BigDecimal calculateInterest() {
        if (this.overdraftUsed.compareTo(BigDecimal.ZERO) == 0 || this.overdraftStartTime == null) {
            return BigDecimal.ZERO;
        }

        // 计算透支天数
        long days = ChronoUnit.DAYS.between(this.overdraftStartTime, LocalDateTime.now());
        
        // 扣除免息天数
        long chargeableDays = days - this.interestFreeDays;
        if (chargeableDays <= 0) {
            return BigDecimal.ZERO;
        }

        // 计算利息：透支金额 * 日利率 * 天数
        return this.overdraftUsed
            .multiply(this.interestRate)
            .multiply(BigDecimal.valueOf(chargeableDays))
            .setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 支付利息
     * @param interest 利息金额
     * @throws InsufficientBalanceException 余额不足异常
     */
    public void payInterest(BigDecimal interest) throws InsufficientBalanceException {
        if (this.balance.compareTo(interest) < 0) {
            throw new InsufficientBalanceException("余额不足，无法支付利息");
        }
        this.balance = this.balance.subtract(interest);
    }

    /**
     * 冻结钱包
     */
    public void freezeWallet() {
        this.status = "FROZEN";
    }

    /**
     * 解冻钱包
     */
    public void unfreezeWallet() {
        this.status = "NORMAL";
    }

    /**
     * 设置VIP
     * @param overdraftLimit 透支额度
     */
    public void setAsVip(BigDecimal overdraftLimit) {
        this.isVip = true;
        this.overdraftLimit = overdraftLimit;
    }

    /**
     * 取消VIP
     */
    public void cancelVip() {
        this.isVip = false;
        this.overdraftLimit = BigDecimal.ZERO;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 验证金额有效性
     * @param amount 金额
     * @throws InvalidAmountException 金额无效异常
     */
    private void validateAmount(BigDecimal amount) throws InvalidAmountException {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new InvalidAmountException("金额必须大于0");
        }
    }

    /**
     * 检查钱包状态
     * @throws WalletFrozenException 钱包冻结异常
     */
    private void checkWalletStatus() throws WalletFrozenException {
        if ("FROZEN".equals(this.status) || "LOCKED".equals(this.status)) {
            throw new WalletFrozenException("钱包已冻结或锁定，无法进行操作");
        }
    }

    /**
     * 计算提现时应扣除的奖励金额
     * @param withdrawAmount 提现金额
     * @return 应扣除的奖励金额
     */
    private BigDecimal calculateBonusToDeduct(BigDecimal withdrawAmount) {
        if (this.bonusAmount.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        // 按比例扣除奖励：(提现金额 / 总余额) * 总奖励
        if (this.balance.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal ratio = withdrawAmount.divide(this.balance, 4, RoundingMode.HALF_UP);
        BigDecimal deduction = this.bonusAmount.multiply(ratio).setScale(2, RoundingMode.HALF_UP);

        // 不能超过实际奖励金额
        return deduction.min(this.bonusAmount);
    }
}
